package net.homelinux.chaoswg.io.renga.core.gui.operations.reader;

import java.io.File;
import java.io.PrintStream;
import java.util.List;
import java.util.SortedSet;
import java.util.Vector;

import net.homelinux.chaoswg.io.renga.core.gui.operations.CompositeOperation;
import net.homelinux.chaoswg.io.renga.core.gui.operations.FunctionInputOperation;
import net.homelinux.chaoswg.io.renga.core.gui.operations.FunctionOutputOperation;
import net.homelinux.chaoswg.io.renga.core.gui.operations.Operation;
import net.homelinux.chaoswg.io.renga.core.registries.ConnectionRegistry;
import net.homelinux.chaoswg.io.renga.core.registries.OperationLoadRegistry;
import net.homelinux.chaoswg.io.renga.core.registries.ReaderRegistry;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

public class GlobalIO {
    @SuppressWarnings("unchecked")
    public Operation apply (final Element rootOperationElement) {
        Operation op = null;
        final ReaderRegistry orr = ReaderRegistry.getOperationRegistry();

        Class<? extends Operation> clazz = null;
        try {
            clazz = ((Class<? extends Operation>)Class.forName(rootOperationElement.getAttributeValue("type")));
        } catch (Exception excp) {
            excp.printStackTrace();
        }
        if (clazz != null) {
            final OperationReader or = ((OperationReader)orr.getOperationReader( clazz ));

            op = or.apply(rootOperationElement);
        }

        return op;
    }

    @SuppressWarnings("unchecked")
    public List<Operation> apply (final Document doc) {
        final List<Operation> toReturn = new Vector<Operation>();
        final List<Element> rootNodes = doc.getRootElement().getChildren("operation");

        for (final Element e : rootNodes) {
            toReturn.add(apply (e));
        }

        final OperationLoadRegistry olr = OperationLoadRegistry.getOperationRegistry();
        final ConnectionRegistry cr = ConnectionRegistry.getConnectoRegistry();

        final SortedSet<Integer> ids = olr.getKeys();
        
        for (final Integer id : ids) {
            final Operation op = olr.getOperationReader(id);
            final Element arg = cr.getElement(op);

            final List<Element> connections = arg.getChild("connections").getChildren("connection");

            for (final Element con : connections) {
                op.connect(Integer.parseInt(con.getAttributeValue("input")), olr.getOperationReader(Integer.parseInt(con.getChildText("id"))), 
                        Integer.parseInt(con.getChildText("outputNumber")));
            }
            
            if (op instanceof FunctionOutputOperation) {
                FunctionOutputOperation foo = ((FunctionOutputOperation)op);
                foo.setSuperOperation(((CompositeOperation)olr.getOperationReader(Integer.parseInt(arg.getChildText("superOperation")))));
            } 
            
            if (op instanceof FunctionInputOperation) {
                FunctionInputOperation fio = ((FunctionInputOperation)op);
                fio.setSuperOperation(((CompositeOperation)olr.getOperationReader(Integer.parseInt(arg.getChildText("superOperation")))));
            }
        }
        
        Operation.setNextId(ids.last() + 1);
        
        
        olr.clearRegistry();
        cr.clearRegistry();

        return toReturn;
    }
    
    public List<Operation> apply (final File f) {
        final SAXBuilder builder  = new SAXBuilder ();
        
        Document doc = null;
        
        try {
            doc = builder.build(f);
            return this.apply (doc);
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return null;        
    }
    
    public boolean write (final CompositeOperation co, final File f) {
      XMLOutputter outputter = new XMLOutputter();
      outputter.setFormat(Format.getPrettyFormat());
      
      Document doc = new Document();
      Element operations = new Element ("operations");
      doc.setRootElement(operations);
      operations.addContent(co.writeYourself());
      
      try {
          outputter.output(doc, new PrintStream(f) );
      } catch (Exception e) {
          e.printStackTrace();
          return false;
      }
      return true;
    }
}
